package com.gitee.wsl.struct.attribute.pairs

import com.gitee.wsl.ext.map.getOrDefault
import com.gitee.wsl.struct.attribute.pairs.Itertools.combinations


internal class CombinationStorage(private val n: Int) {
    private val nodes = LinkedHashMap<String, Node>()
    /* itemIdCombinations = Stream.generate { HashSet<List<String?>?>() }
         .limit(n.toLong())
         .collect(Collectors.toList())*/
    val itemIdCombinations: Array<MutableSet<List<String>>> = Array(n){ mutableSetOf() }

    val length: Int
        get() = itemIdCombinations[itemIdCombinations.size - 1].size

    fun getNodeOrCreateNew(item: Item): Node {
        return nodes.getOrDefault(item.itemId, Node(item.itemId))
    }

    fun addSequenceCombinations(sequence: List<Item>) {
        for (i in 1 until n + 1) {
            combinations(sequence, i).forEach { combination: List<Item> ->
                    addCombination(
                        combination
                    )
                }
        }
    }

    private fun addCombination(combination: List<Item>) {
        val combinationSize = combination.size
        if (combinationSize == 0) {
            throw RuntimeException("Combination is empty")
        }
        itemIdCombinations[combinationSize - 1].add(combination.map(Item::itemId))
        if (combinationSize == 1 && !nodes.containsKey(combination[0].itemId)) {
            nodes[combination[0].itemId] = Node(
                combination[0].itemId
            )
            return
        }
        val itemIds = combination.map(Item::itemId)

        for (i in itemIds.indices) {
            val currentNode = nodes[itemIds[i]]
            currentNode!!.increaseCounter()
            currentNode.addInboundItemIds(itemIds.subList(0, i))
            currentNode.addOutboundItemIds(itemIds.subList(i + 1, itemIds.size))
        }
    }
}